/*
 * Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   * Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *   * Neither the name of Redis nor the names of its contributors may be used
 *     to endorse or promote products derived from this software without
 *     specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef __REDIS_H
#define __REDIS_H

#ifdef __cplusplus
extern "C"
{
#endif

#include "../lib/fmacros.h"
#include "../lib/redis.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <limits.h>
#include <unistd.h>
#include <errno.h>
#include <inttypes.h>
#include <pthread.h>
#include <syslog.h>
#include <signal.h>

    typedef long long mstime_t; /* millisecond time type. */

#include "../lib/sds.h"     /* Dynamic safe strings */
#include "../lib/dict.h"    /* Hash tables */
#include "../lib/adlist.h"  /* Linked lists */
#include "../lib/zmalloc.h" /* total memory usage aware version of malloc/free */
#include "../lib/ziplist.h" /* Compact list data structure */
#include "../lib/intset.h"  /* Compact integer set structure */
#include "../lib/util.h"    /* Misc functions useful in many places */
#include "../lib/quicklist.h"

    /* Error codes */
#define C_OK                    0
#define C_ERR                   -1

    /* Static server configuration */
#define CONFIG_DEFAULT_HZ        10      /* Time interrupt calls/sec. */
#define CONFIG_MIN_HZ            1
#define CONFIG_MAX_HZ            500
#define CONFIG_DEFAULT_DBNUM     1
#define CONFIG_MAX_LINE    1024
#define CRON_DBS_PER_CALL 1

#define OBJ_SHARED_INTEGERS 10000

#define CONFIG_RUN_ID_SIZE 40
#define CONFIG_DEFAULT_MAXMEMORY 1024LL*(1024*1024)
#define CONFIG_DEFAULT_MAXMEMORY_SAMPLES 5
#define CONFIG_DEFAULT_ACTIVE_REHASHING 1

#define ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP 20 /* Loopkups per loop. */
#define ACTIVE_EXPIRE_CYCLE_FAST_DURATION 1000 /* Microseconds */
#define ACTIVE_EXPIRE_CYCLE_SLOW_TIME_PERC 25 /* CPU max % for keys collection */
#define ACTIVE_EXPIRE_CYCLE_SLOW 0
#define ACTIVE_EXPIRE_CYCLE_FAST 1

    /* Instantaneous metrics tracking. */
#define STATS_METRIC_SAMPLES 16     /* Number of samples per metric. */
#define STATS_METRIC_COMMAND 0      /* Number of commands executed. */
#define STATS_METRIC_COUNT 3

    /* Protocol and I/O related defines */
#define PROTO_MAX_QUERYBUF_LEN  (1024*1024*1024) /* 1GB max query buffer. */
#define PROTO_IOBUF_LEN         (1024*16)  /* Generic I/O buffer size */
#define PROTO_REPLY_CHUNK_BYTES (16*1024) /* 16k output buffer */
#define PROTO_INLINE_MAX_SIZE   (1024*64) /* Max size of inline reads */
#define PROTO_MBULK_BIG_ARG     (1024*32)
#define LONG_STR_SIZE      21          /* Bytes needed for long -> str */

    /* Hash table parameters */
#define HASHTABLE_MIN_FILL        10      /* Minimal hash table fill 10% */

    /* Command flags. Please check the command table defined in the redis.c file
     * for more information about the meaning of every flag. */
#define CMD_WRITE 1                   /* "w" flag */
#define CMD_READONLY 2                /* "r" flag */
#define CMD_DENYOOM 4                 /* "m" flag */
#define CMD_NOT_USED_1 8              /* no longer used flag */
#define CMD_ADMIN 16                  /* "a" flag */
#define CMD_RANDOM 128                /* "R" flag */
#define CMD_SORT_FOR_SCRIPT 256       /* "S" flag */
#define CMD_STALE 1024                /* "t" flag */
#define CMD_FAST 8192                 /* "F" flag */

    /* Object types */
#define OBJ_STRING 0
#define OBJ_LIST 1
#define OBJ_SET 2
#define OBJ_ZSET 3
#define OBJ_HASH 4

    /* Objects encoding. Some kind of objects like Strings and Hashes can be
     * internally represented in multiple ways. The 'encoding' field of the object
     * is set to one of this fields for this object. */
#define OBJ_ENCODING_RAW 0     /* Raw representation */
#define OBJ_ENCODING_INT 1     /* Encoded as integer */
#define OBJ_ENCODING_HT 2      /* Encoded as hash table */
#define OBJ_ENCODING_ZIPMAP 3  /* Encoded as zipmap */
#define OBJ_ENCODING_LINKEDLIST 4 /* Encoded as regular linked list */
#define OBJ_ENCODING_ZIPLIST 5 /* Encoded as ziplist */
#define OBJ_ENCODING_INTSET 6  /* Encoded as intset */
#define OBJ_ENCODING_SKIPLIST 7  /* Encoded as skiplist */
#define OBJ_ENCODING_EMBSTR 8  /* Embedded sds string encoding */
#define OBJ_ENCODING_QUICKLIST 9 /* Encoded as linked list of ziplists */

    /* List related stuff */
#define LIST_HEAD 0
#define LIST_TAIL 1

    /* Sort operations */
#define SORT_OP_GET 0

    /* Anti-warning macro... */
#define UNUSED(V) ((void) V)

#define ZSKIPLIST_MAXLEVEL 32 /* Should be enough for 2^32 elements */
#define ZSKIPLIST_P 0.25      /* Skiplist P = 1/4 */

    /* Zip structure related defaults */
#define OBJ_HASH_MAX_ZIPLIST_ENTRIES 512
#define OBJ_HASH_MAX_ZIPLIST_VALUE 64
#define OBJ_SET_MAX_INTSET_ENTRIES 512
#define OBJ_ZSET_MAX_ZIPLIST_ENTRIES 128
#define OBJ_ZSET_MAX_ZIPLIST_VALUE 64

    /* List defaults */
#define OBJ_LIST_MAX_ZIPLIST_SIZE -2
#define OBJ_LIST_COMPRESS_DEPTH 0

    /* Sets operations codes */
#define SET_OP_UNION 0
#define SET_OP_DIFF 1
#define SET_OP_INTER 2

    /* Redis maxmemory strategies */
#define MAXMEMORY_VOLATILE_LRU 0
#define MAXMEMORY_VOLATILE_TTL 1
#define MAXMEMORY_VOLATILE_RANDOM 2
#define MAXMEMORY_ALLKEYS_LRU 3
#define MAXMEMORY_ALLKEYS_RANDOM 4
#define MAXMEMORY_NO_EVICTION 5
#define CONFIG_DEFAULT_MAXMEMORY_POLICY MAXMEMORY_ALLKEYS_LRU


    /* Units */
#define UNIT_SECONDS 0
#define UNIT_MILLISECONDS 1

    /* Command call flags, see call() function */
#define CMD_CALL_NONE 0
#define CMD_CALL_STATS (1<<1)
#define CMD_CALL_FULL (CMD_CALL_STATS)

    /* Using the following macro you can run code inside serverCron() with the
     * specified period, specified in milliseconds.
     * The actual resolution depends on server.hz. */
#define run_with_period(_ms_) if ((_ms_ <= 1000/server.hz) || !(server.cronloops%((_ms_)/(1000/server.hz))))

    /*-----------------------------------------------------------------------------
     * Data types
     *----------------------------------------------------------------------------*/

    /* A redis object, that is a type able to hold a string / list / set */

    /* The actual Redis Object */


    /* Macro used to obtain the current LRU clock.
     * If the current resolution is lower than the frequency we refresh the
     * LRU clock (as it should be in production servers) we return the
     * precomputed value, otherwise we need to resort to a function call. */
#define LRU_CLOCK() ((1000/server.hz <= LRU_CLOCK_RESOLUTION) ? server.lruclock : getLRUClock())

    /* Macro used to initialize a Redis object allocated on the stack.
     * Note that this macro is taken near the structure definition to make sure
     * we'll update it when the structure is changed, to avoid bugs like
     * bug #85 introduced exactly in this way. */
#define initStaticStringObject(_var,_ptr) do { \
    _var.refcount = 1; \
    _var.type = OBJ_STRING; \
    _var.encoding = OBJ_ENCODING_RAW; \
    _var.ptr = _ptr; \
} while(0)

    /* To improve the quality of the LRU approximation we take a set of keys
     * that are good candidate for eviction across freeMemoryIfNeeded() calls.
     *
     * Entries inside the eviciton pool are taken ordered by idle time, putting
     * greater idle times to the right (ascending order).
     *
     * Empty entries have the key pointer set to NULL. */
#define MAXMEMORY_EVICTION_POOL_SIZE 16

struct evictionPoolEntry
    {
        unsigned long long idle; /* Object idle time. */
        sds key; /* Key name. */
    };

    /* Redis database representation. There are multiple databases identified
     * by integers from 0 (the default database) up to the max configured
     * database. The database number is the 'id' field in the structure. */

    struct sharedObjectsStruct
    {
        robj *minstring, *maxstring;
        robj *integers[OBJ_SHARED_INTEGERS];
    };

    /* ZSETs use a specialized version of Skiplists */
    typedef struct zskiplistNode
    {
        robj *obj;
        double score;
        struct zskiplistNode *backward;

        struct zskiplistLevel
        {
            struct zskiplistNode *forward;
            unsigned int span;
        } level[];
    } zskiplistNode;

    typedef struct zskiplist
    {
        struct zskiplistNode *header, *tail;
        unsigned long length;
        int level;
    } zskiplist;

    typedef struct zset
    {
        dict *dict;
        zskiplist *zsl;
    } zset;

    /*-----------------------------------------------------------------------------
     * Global server state
     *----------------------------------------------------------------------------*/

    /* AIX defines hz to __hz, we don't use this define and in order to allow
     * Redis build on AIX we need to undef it. */
#ifdef _AIX
#undef hz
#endif

    struct redisServer
    {
        /* General */
        int hz; /* serverCron() calls frequency in hertz */
        redisDb *db;
        dict *commands; /* Command table */
        unsigned lruclock : LRU_BITS; /* Clock for LRU eviction */
        int activerehashing; /* Incremental rehash in serverCron() */
        int arch_bits; /* 32 or 64 depending on sizeof(long) */
        int cronloops; /* Number of times the cron function run */

        /* Fields used only for stats */
        time_t stat_starttime; /* Server start time */
        long long stat_numcommands; /* Number of processed commands */
        long long stat_numconnections; /* Number of connections received */
        long long stat_expiredkeys; /* Number of expired keys */
        long long stat_evictedkeys; /* Number of evicted keys (maxmemory) */
        long long stat_keyspace_hits; /* Number of successful lookups of keys */
        long long stat_keyspace_misses; /* Number of failed lookups of keys */
        size_t stat_peak_memory; /* Max used memory record */
        long long stat_fork_time; /* Time needed to perform latest fork() */
        size_t resident_set_size; /* RSS sampled in serverCron(). */

        /* The following two are used to track instantaneous metrics, like
         * number of operations per second, network traffic. */
        struct
        {
            long long last_sample_time; /* Timestamp of last sample in ms */
            long long last_sample_count; /* Count in last sample */
            long long samples[STATS_METRIC_SAMPLES];
            int idx;
        } inst_metric[STATS_METRIC_COUNT];
        /* Configuration */
        int active_expire_enabled; /* Can be disabled for testing purposes. */
        int dbnum; /* Total number of configured DBs */

        /* Limits */
        unsigned long long maxmemory; /* Max number of memory bytes to use */
        int maxmemory_policy; /* Policy for key eviction */
        int maxmemory_samples; /* Pricision of random sampling */

        /* Sort parameters - qsort_r() is only available under BSD so we
         * have to take this state global, in order to pass it to sortCompare() */
        int sort_desc;
        int sort_alpha;
        int sort_bypattern;
        int sort_store;
        /* Zip structure config, see redis.conf for more information  */
        size_t hash_max_ziplist_entries;
        size_t hash_max_ziplist_value;
        size_t set_max_intset_entries;
        size_t zset_max_ziplist_entries;
        size_t zset_max_ziplist_value;
        size_t hll_sparse_max_bytes;
        /* List parameters */
        int list_max_ziplist_size;
        int list_compress_depth;
        /* time cache */
        time_t unixtime; /* Unix time sampled every cron cycle. */
        long long mstime; /* Like 'unixtime' but with milliseconds resolution. */

        /* System hardware info */
        size_t system_memory_size; /* Total memory in system as reported by OS */
    };

    typedef struct _redisSortObject
    {
        robj *obj;

        union
        {
            double score;
            robj *cmpobj;
        } u;
    } redisSortObject;

    typedef struct _redisSortOperation
    {
        int type;
        robj *pattern;
    } redisSortOperation;

    /* Structure to hold list iteration abstraction. */
    typedef struct
    {
        robj *subject;
        unsigned char encoding;
        unsigned char direction; /* Iteration direction */
        quicklistIter *iter;
    } listTypeIterator;

    /* Structure for an entry while iterating over a list. */
    typedef struct
    {
        listTypeIterator *li;
        quicklistEntry entry; /* Entry in quicklist */
    } listTypeEntry;

    /* Structure to hold set iteration abstraction. */
    typedef struct
    {
        robj *subject;
        int encoding;
        int ii; /* intset iterator */
        dictIterator *di;
    } setTypeIterator;

    /* Structure to hold hash iteration abstraction. Note that iteration over
     * hashes involves both fields and values. Because it is possible that
     * not both are required, store pointers in the iterator to avoid
     * unnecessary memory allocation for fields/values. */
    typedef struct
    {
        robj *subject;
        int encoding;

        unsigned char *fptr, *vptr;

        dictIterator *di;
        dictEntry *de;
    } hashTypeIterator;

#define OBJ_HASH_KEY 1
#define OBJ_HASH_VALUE 2

    /*-----------------------------------------------------------------------------
     * Extern declarations
     *----------------------------------------------------------------------------*/

    extern struct redisServer server;
    extern struct sharedObjectsStruct shared;
    extern dictType setDictType;
    extern dictType zsetDictType;
    extern dictType dbDictType;
    extern double R_Zero, R_PosInf, R_NegInf, R_Nan;
    extern dictType hashDictType;

    /*-----------------------------------------------------------------------------
     * Functions prototypes
     *----------------------------------------------------------------------------*/

    /* Utils */
    long long ustime ( void );
    long long mstime ( void );

    /* networking.c -- Networking and Client related operations */

    void freeClientArgv ( client *c );
    int getClientType ( client *c );
    int getClientTypeByName ( char *name );
    char *getClientTypeName ( int class );

    void addReply ( client *c, robj *obj );
    void addReplyString ( client *c, char *s, size_t len );
    void addReplyLongLong ( client *c, long long ll );
    void addReplyNULL ( client *c );
    void addReplySds ( client *c, sds s );
    void addReplyDouble ( client *c, double d );

    void addReplyJsonLongLong ( client *c, int type, long long ll, double d );
    void addReplyJsonString ( client *c, int type, char *key, size_t key_len, double d );
    void addReplyJson ( client *c, int type, robj *obj, double d );
    void addReplyJsonHead ( client *c );
    void addReplyJsonTail ( client *c );
    void addReplyJsonSep ( client *c );
    int outOfRange ( client *c );

    /* List data type */
    void listTypeTryConversion ( robj *subject, robj *value );
    void listTypePush ( robj *subject, robj *value, int where );
    robj *listTypePop ( robj *subject, int where );
    unsigned long listTypeLength ( robj *subject );
    listTypeIterator *listTypeInitIterator ( robj *subject, long index, unsigned char direction );
    void listTypeReleaseIterator ( listTypeIterator *li );
    int listTypeNext ( listTypeIterator *li, listTypeEntry *entry );
    robj *listTypeGet ( listTypeEntry *entry );
    void listTypeInsert ( listTypeEntry *entry, robj *value, int where );
    int listTypeEqual ( listTypeEntry *entry, robj *o );
    void listTypeDelete ( listTypeIterator *iter, listTypeEntry *entry );
    void listTypeConvert ( robj *subject, int enc );
    int popGenericCommand ( client *c, int where );
    void signalListAsReady ( redisDb *db, robj *key );

    /* Redis object implementation */
    void decrRefCount ( robj *o );
    void decrRefCountVoid ( void *o );
    void incrRefCount ( robj *o );
    robj *resetRefCount ( robj *obj );
    void freeStringObject ( robj *o );
    void freeListObject ( robj *o );
    void freeSetObject ( robj *o );
    void freeZsetObject ( robj *o );
    void freeHashObject ( robj *o );
    robj *createObject ( int type, void *ptr );
    robj *createStringObject ( const char *ptr, size_t len );
    robj *createRawStringObject ( const char *ptr, size_t len );
    robj *createEmbeddedStringObject ( const char *ptr, size_t len );
    robj *dupStringObject ( robj *o );
    int isObjectRepresentableAsLongLong ( robj *o, long long *llongval );
    robj *tryObjectEncoding ( robj *o );
    robj *getDecodedObject ( robj *o );
    size_t stringObjectLen ( robj *o );
    robj *createStringObjectFromLongLong ( long long value );
    robj *createStringObjectFromLongDouble ( long double value, int humanfriendly );
    robj *createQuicklistObject ( void );
    robj *createZiplistObject ( void );
    robj *createSetObject ( void );
    robj *createIntsetObject ( void );
    robj *createHashObject ( void );
    robj *createZsetObject ( void );
    robj *createZsetZiplistObject ( void );
    int getLongFromObject ( robj *o, long *target );
    int checkType ( client *c, robj *o, int type );
    int getDoubleFromObject ( robj *o, double *target );
    int getLongLongFromObject ( robj *o, long long *target );
    int getLongDoubleFromObject ( robj *o, long double *target );
    char *strEncoding ( int encoding );
    int compareStringObjects ( robj *a, robj *b );
    int collateStringObjects ( robj *a, robj *b );
    int equalStringObjects ( robj *a, robj *b );
    unsigned long long estimateObjectIdleTime ( robj *o );
#define sdsEncodedObject(objptr) (objptr->encoding == OBJ_ENCODING_RAW || objptr->encoding == OBJ_ENCODING_EMBSTR)

    /* Sorted sets data type */

    /* Struct to hold a inclusive/exclusive range spec by score comparison. */
    typedef struct
    {
        double min, max;
        int minex, maxex; /* are min or max exclusive? */
    } zrangespec;

    /* Struct to hold an inclusive/exclusive range spec by lexicographic comparison. */
    typedef struct
    {
        robj *min, *max; /* May be set to shared.(minstring|maxstring) */
        int minex, maxex; /* are min or max exclusive? */
    } zlexrangespec;

    zskiplist *zslCreate ( void );
    void zslFree ( zskiplist *zsl );
    zskiplistNode *zslInsert ( zskiplist *zsl, double score, robj *obj );
    unsigned char *zzlInsert ( unsigned char *zl, robj *ele, double score );
    int zslDelete ( zskiplist *zsl, double score, robj *obj );
    zskiplistNode *zslFirstInRange ( zskiplist *zsl, zrangespec *range );
    zskiplistNode *zslLastInRange ( zskiplist *zsl, zrangespec *range );
    double zzlGetScore ( unsigned char *sptr );
    void zzlNext ( unsigned char *zl, unsigned char **eptr, unsigned char **sptr );
    void zzlPrev ( unsigned char *zl, unsigned char **eptr, unsigned char **sptr );
    unsigned int zsetLength ( robj *zobj );
    void zsetConvert ( robj *zobj, int encoding );
    void zsetConvertToZiplistIfNeeded ( robj *zobj, size_t maxelelen );
    int zsetScore ( robj *zobj, robj *member, double *score );
    unsigned long zslGetRank ( zskiplist *zsl, double score, robj *o );

    /* Core functions */
    int freeMemoryIfNeeded ( void );
    int processCommand ( client *c );
    struct redisCommand *lookupCommand ( sds name );
    struct redisCommand *lookupCommandByCString ( char *s );
    struct redisCommand *lookupCommandOrOriginal ( sds name );
    int call ( client *c );

    void updateDictResizePolicy ( void );
    int htNeedsResize ( dict *dict );
    void populateCommandTable ( void );
    void resetCommandTableStats ( void );
    void updateCachedTime ( void );
    void resetServerStats ( void );
    unsigned int getLRUClock ( void );
    const char *evictPolicyToString ( void );

#define RESTART_SERVER_NONE 0
#define RESTART_SERVER_GRACEFULLY (1<<0)     /* Do proper shutdown. */
#define RESTART_SERVER_CONFIG_REWRITE (1<<1) /* CONFIG REWRITE before restart.*/
    int restartServer ( int flags, mstime_t delay );

    /* Set data type */
    robj *setTypeCreate ( robj *value );
    int setTypeAdd ( robj *subject, robj *value );
    int setTypeRemove ( robj *subject, robj *value );
    int setTypeIsMember ( robj *subject, robj *value );
    setTypeIterator *setTypeInitIterator ( robj *subject );
    void setTypeReleaseIterator ( setTypeIterator *si );
    int setTypeNext ( setTypeIterator *si, robj **objele, int64_t *llele );
    robj *setTypeNextObject ( setTypeIterator *si );
    int setTypeRandomElement ( robj *setobj, robj **objele, int64_t *llele );
    unsigned long setTypeRandomElements ( robj *set, unsigned long count, robj *aux_set );
    unsigned long setTypeSize ( robj *subject );
    void setTypeConvert ( robj *subject, int enc );

    /* Hash data type */
    void hashTypeConvert ( robj *o, int enc );
    void hashTypeTryConversion ( robj *subject, robj **argv, int start, int end );
    void hashTypeTryObjectEncoding ( robj *subject, robj **o1, robj **o2 );
    robj *hashTypeGetObject ( robj *o, robj *key );
    int hashTypeExists ( robj *o, robj *key );
    int hashTypeSet ( robj *o, robj *key, robj *value );
    int hashTypeDelete ( robj *o, robj *key );
    unsigned long hashTypeLength ( robj *o );
    hashTypeIterator *hashTypeInitIterator ( robj *subject );
    void hashTypeReleaseIterator ( hashTypeIterator *hi );
    int hashTypeNext ( hashTypeIterator *hi );
    void hashTypeCurrentFromZiplist ( hashTypeIterator *hi, int what,
                                      unsigned char **vstr,
                                      unsigned int *vlen,
                                      long long *vll );
    void hashTypeCurrentFromHashTable ( hashTypeIterator *hi, int what, robj **dst );
    robj *hashTypeCurrentObject ( hashTypeIterator *hi, int what );
    robj *hashTypeLookupWriteOrCreate ( client *c, robj *key );

    /* db.c -- Keyspace access API */
    int removeExpire ( redisDb *db, robj *key );
    int expireIfNeeded ( redisDb *db, robj *key );
    long long getExpire ( redisDb *db, robj *key );
    void setExpire ( redisDb *db, robj *key, long long when );
    robj *lookupKey ( redisDb *db, robj *key );
    robj *lookupKeyRead ( redisDb *db, robj *key );
    robj *lookupKeyWrite ( redisDb *db, robj *key );
    robj *lookupKeyReadOrReply ( client *c, robj *key, robj *reply );
    robj *lookupKeyWriteOrReply ( client *c, robj *key, robj *reply );
    void dbAdd ( redisDb *db, robj *key, robj *val );
    void dbOverwrite ( redisDb *db, robj *key, robj *val );
    void setKey ( redisDb *db, robj *key, robj *val );
    int dbExists ( redisDb *db, robj *key );
    robj *dbRandomKey ( redisDb *db );
    int dbDelete ( redisDb *db, robj *key );
    robj *dbUnshareStringValue ( redisDb *db, robj *key, robj *o );
    long long emptyDb ( void(callback ) ( void* ) );
    int selectDb ( client *c, int id );
    void signalModifiedKey ( redisDb *db, robj *key );
    void signalFlushedDb ( int dbid );
    unsigned int getKeysInSlot ( unsigned int hashslot, robj **keys, unsigned int count );
    unsigned int countKeysInSlot ( unsigned int hashslot );
    unsigned int delKeysInSlot ( unsigned int hashslot );
    int verifyClusterConfigWithData ( void );
    void scanGenericCommand ( client *c, robj *o, unsigned long cursor );
    int parseScanCursor ( client *c, robj *o, unsigned long *cursor );

    /* API to get key arguments from commands */
    int *getKeysFromCommand ( struct redisCommand *cmd, robj **argv, int argc, int *numkeys );
    void getKeysFreeResult ( int *result );
    int *zunionInterGetKeys ( struct redisCommand *cmd, robj **argv, int argc, int *numkeys );
    int *sortGetKeys ( struct redisCommand *cmd, robj **argv, int argc, int *numkeys );

    /* Commands prototypes */
    int setCommand ( client *c );
    int setnxCommand ( client *c );
    int setexCommand ( client *c );
    int psetexCommand ( client *c );
    int getCommand ( client *c );
    int delCommand ( client *c );
    int existsCommand ( client *c );
    int setbitCommand ( client *c );
    int getbitCommand ( client *c );
    int bitfieldCommand ( client *c );
    int setrangeCommand ( client *c );
    int getrangeCommand ( client *c );
    int incrCommand ( client *c );
    int decrCommand ( client *c );
    int incrbyCommand ( client *c );
    int decrbyCommand ( client *c );
    int incrbyfloatCommand ( client *c );
    int selectCommand ( client *c );
    int randomkeyCommand ( client *c );
    int keysCommand ( client *c );
    int scanCommand ( client *c );
    int dbsizeCommand ( client *c );
    int moveCommand ( client *c );
    int renamenxCommand ( client *c );
    int lpushCommand ( client *c );
    int rpushCommand ( client *c );
    int lpushxCommand ( client *c );
    int rpushxCommand ( client *c );
    int linsertCommand ( client *c );
    int lpopCommand ( client *c );
    int rpopCommand ( client *c );
    int llenCommand ( client *c );
    int lindexCommand ( client *c );
    int lrangeCommand ( client *c );
    int ltrimCommand ( client *c );
    int typeCommand ( client *c );
    int lsetCommand ( client *c );
    int saddCommand ( client *c );
    int sremCommand ( client *c );
    int smoveCommand ( client *c );
    int sismemberCommand ( client *c );
    int scardCommand ( client *c );
    int spopCommand ( client *c );
    int srandmemberCommand ( client *c );
    int sinterCommand ( client *c );
    int sinterstoreCommand ( client *c );
    int sunionCommand ( client *c );
    int sunionstoreCommand ( client *c );
    int sdiffCommand ( client *c );
    int sdiffstoreCommand ( client *c );
    int sscanCommand ( client *c );
    int flushdbCommand ( client *c );
    int flushallCommand ( client *c );
    int sortCommand ( client *c );
    int lremCommand ( client *c );
    int rpoplpushCommand ( client *c );
    int infoCommand ( client *c );
    int mgetCommand ( client *c );
    int expireCommand ( client *c );
    int expireatCommand ( client *c );
    int pexpireCommand ( client *c );
    int pexpireatCommand ( client *c );
    int getsetCommand ( client *c );
    int ttlCommand ( client *c );
    int pttlCommand ( client *c );
    int persistCommand ( client *c );
    int msetCommand ( client *c );
    int msetnxCommand ( client *c );
    int zaddCommand ( client *c );
    int zincrbyCommand ( client *c );
    int zrangeCommand ( client *c );
    int zrangebyscoreCommand ( client *c );
    int zrevrangebyscoreCommand ( client *c );
    int zrangebylexCommand ( client *c );
    int zrevrangebylexCommand ( client *c );
    int zcountCommand ( client *c );
    int zlexcountCommand ( client *c );
    int zrevrangeCommand ( client *c );
    int zcardCommand ( client *c );
    int zremCommand ( client *c );
    int zscoreCommand ( client *c );
    int zremrangebyscoreCommand ( client *c );
    int zremrangebylexCommand ( client *c );
    int discardCommand ( client *c );
    int appendCommand ( client *c );
    int strlenCommand ( client *c );
    int zrankCommand ( client *c );
    int zrevrankCommand ( client *c );
    int hsetCommand ( client *c );
    int hsetnxCommand ( client *c );
    int hgetCommand ( client *c );
    int hmsetCommand ( client *c );
    int hmgetCommand ( client *c );
    int hdelCommand ( client *c );
    int hlenCommand ( client *c );
    int hstrlenCommand ( client *c );
    int zremrangebyrankCommand ( client *c );
    int zunionstoreCommand ( client *c );
    int zinterstoreCommand ( client *c );
    int zscanCommand ( client *c );
    int hkeysCommand ( client *c );
    int hvalsCommand ( client *c );
    int hgetallCommand ( client *c );
    int hexistsCommand ( client *c );
    int hscanCommand ( client *c );
    int hincrbyCommand ( client *c );
    int hincrbyfloatCommand ( client *c );
    int objectCommand ( client *c );
    int bitopCommand ( client *c );
    int bitcountCommand ( client *c );
    int bitposCommand ( client *c );

#if defined(__GNUC__)
    void *calloc ( size_t count, size_t size ) __attribute__ ( ( deprecated ) );
    void free ( void *ptr ) __attribute__ ( ( deprecated ) );
    void *malloc ( size_t size ) __attribute__ ( ( deprecated ) );
    void *realloc ( void *ptr, size_t size ) __attribute__ ( ( deprecated ) );
#endif

#ifdef __cplusplus
}
#endif

#endif
